package com.hongpu.controller;


import com.alibaba.fastjson2.JSONObject;
import com.hongpu.config.SecurityContextUtil;
import com.hongpu.domain.SysUser;
import com.hongpu.service.SysUserService;
import com.hongpu.utils.JwtUtils;
import com.hongpu.utils.ResultDto;
import com.hongpu.vo.SysMenuVo;
import com.hongpu.vo.SysRoleVo;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.AuthenticationEventPublisher;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.User;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * @author 张玉胜
 * @since 2025年05月13日
 */
@Slf4j
@RestController
@RequestMapping("/auth")
public class AuthController {
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private AuthenticationEventPublisher eventPublisher;
    @Autowired
    SysUserService sysUserService;
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    /**
     * 登录过期时间
     */
    long EXPIRATION_MS = System.currentTimeMillis() + 3600 * 1000 * 8 * 10;

    @PostMapping("/login")
    public ResultDto login(@RequestParam("account") String account, @RequestParam("password") String password) {
        //  log.info("账号account:{}登录",account);
        try {
            Authentication unauthenticated = UsernamePasswordAuthenticationToken.unauthenticated(account, password);
            Authentication authentication = authenticationManager.authenticate(unauthenticated);
            eventPublisher.publishAuthenticationSuccess(authentication);
            User user = (User) authentication.getPrincipal();
            String userAccount = user.getUsername();
            SysUser sysUser = sysUserService.getSysUserByUseraccount(userAccount);
            sysUser.setPassword(null);
            Long userId = sysUser.getId();
            String token = JwtUtils.generateToken(userId, userAccount);
            stringRedisTemplate.opsForValue().set(token, token, EXPIRATION_MS, TimeUnit.MILLISECONDS);
            List<SysRoleVo> sysRoleVos = sysUserService.getRoleIdsByUserId(userId);
            // 根据 roleIds 查询菜单
            List<SysMenuVo> menuVoList = sysUserService.getSysMenusByRoleId(sysRoleVos);
            sysUser.setSysRoleVos(sysRoleVos).setMenuVoList(menuVoList).setRoleIds(sysRoleVos.stream().map(SysRoleVo::getId).collect(Collectors.toList()));
            String redisKey = String.format("auth:user:account:%s", userAccount);
            String redisUser = JSONObject.from(sysUser).toString();
            stringRedisTemplate.opsForValue().getAndDelete(redisKey);
            stringRedisTemplate.opsForValue().set(redisKey, redisUser, EXPIRATION_MS, TimeUnit.MILLISECONDS);
            // System.out.println(stringRedisTemplate.opsForValue().get(redisKey));
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("access_token", token);
            jsonObject.put("token_type", "Bearer");
            jsonObject.put("expires_in", EXPIRATION_MS);
            return ResultDto.ok(jsonObject);
        } catch (AuthenticationException e) {
            e.printStackTrace();
            eventPublisher.publishAuthenticationFailure(e, new UsernamePasswordAuthenticationToken(account, password));
            return ResultDto.fail(String.valueOf(HttpStatus.UNAUTHORIZED.value()), e.getLocalizedMessage());
        }
    }

    /**
     * 注销登录状态
     */
    @GetMapping("/logout")
    public ResultDto logout(HttpServletRequest request) {
        final String AUTHORITY_CLAIM_NAME = "Authorization";
        final String BEARER_TOKEN_STARTS_WITH = "Bearer ";
        String bearerToken = request.getHeader(AUTHORITY_CLAIM_NAME);
        String token = "";
        try {
            if (bearerToken != null) {
                if (bearerToken.startsWith(BEARER_TOKEN_STARTS_WITH)) {
                    token = bearerToken.substring(7);
                } else {
                    token = bearerToken;
                }
                String userAccount = SecurityContextUtil.getUserAccount();
                String redisKey = String.format("auth:user:account:%s", userAccount);
                stringRedisTemplate.opsForValue().getAndDelete(redisKey);
                stringRedisTemplate.delete(token);
                return ResultDto.ok();
            } else {
                return ResultDto.fail("未检测到登录的token");
            }
        } catch (Exception e) {
            return ResultDto.fail(e.getLocalizedMessage());
        }
    }
}